#!/bin/bash
# graudit - Rough code review tool using grep
# Written by Wireghoul - http://www.justanotherhacker.com
# Released under the GPL licence
set -e
set -o pipefail
VERSION='3.1'
basedir=$(dirname "$0")
BINFILE=$(which grep)

# Default values
hidebanner=0
context=1
zimlines="#"
vimlines="#"
color='always'
sigdb='default'
separator='##############################################'
excludefiles='--exclude=*.bz2 --exclude=*.gz --exclude=*.zip --exclude=*.rar --exclude=*.gif --exclude=*.jpg --exclude=*.png'

#Save custom colors
OLD_COLORS=$GREP_COLORS
OLD_COLOR=$GREP_COLOR

if [ ! -x "$BINFILE" ]; then
    echo "Can't find grep, which is a requirement to run graudit"
    exit 2
fi
$BINFILE --exclude-dir=. test "$0" >/dev/null 2>&1
if [ $? -eq 2 ]; then
    echo $?
    echo "graudit requires a newer version of grep (>=2.5.3)"
    exit 2
fi
banner() {
    if [ $hidebanner == 0 ]; then
    echo \
'===========================================================
                                      .___ __  __   
          _________________  __ __  __| _/|__|/  |_ 
         / ___\_` __ \__  \ |  |  \/ __ | | \\_  __\
        / /_/  >  | \// __ \|  |  / /_/ | |  ||  |  
        \___  /|__|  (____  /____/\____ | |__||__|  
       /_____/            \/           \/           
              grep rough audit - static analysis tool
                  v3.1 written by @Wireghoul
=================================[justanotherhacker.com]==='
    fi
}

version () {
    echo "graudit version: $VERSION"
}

usage () {
    banner
    cat <<EOU
Usage: graudit [opts] /path/to/scan

OPTIONS
  -d <dbname> database to use or /path/to/file.db (uses default if not specified)
  -A scan unwanted and difficult (ALL) files
  -x exclude these files (comma separated list: -x *.js,*.sql)
  -i case in-sensitive scan
  -c <num> number of lines of context to display, default is 2

  -B supress banner
  -L vim friendly lines
  -b colour blind friendly template
  -z supress colors
  -Z high contrast colors
  
  -l lists databases available
  -v prints version number
  -h prints this help screen

EOU
}

listdb () {
    set +e
    set +o pipefail
    banner
    if [ -n "$GRDIR" ] && [ -d "$GRDIR" ]; then
        ls -1 "$GRDIR"/*.db 2>/dev/null
    fi
    if [ -d /usr/share/graudit/ ]; then
        ls -1 /usr/share/graudit/*.db 2>/dev/null
    fi
    if [ -d ~/.graudit/ ]; then
        ls -1 ~/.graudit/*.db 2>/dev/null
    fi
    if [ -d "$basedir"/signatures/ ]; then
        ls -1 "$basedir"/signatures/*.db 2>/dev/null
    fi
    if [ -d "$basedir"/misc/ ]; then
        ls -1 "$basedir"/misc/*.db 2>/dev/null
    fi
    if [ -d ~/graudit/signatures/ ]; then
        ls -1 ~/graudit/signatures/*.db 2>/dev/null
    fi
}

while getopts "AbBhvilLzZd:c:x:" opt; do
    case $opt in
        B)
            hidebanner=1
        ;;
        h)
            usage
            exit 1
        ;;
        v)
            version
            exit 0
        ;;
        l)
            listdb
            exit 0
        ;;
        b)
            export GREP_COLORS='ms=93:sl=:cx=:fn=94:ln=92:bn=92:se=32'
            export GREP_COLOR='1;35'
        ;;
        z)
            color='none'
        ;;
        Z)
            export GREP_COLORS='ms=41;01;37:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36'
            export GREP_COLOR='1;37;41;'
        ;;
        c)
            context="$OPTARG"
        ;;
        d)
            sigdb="$OPTARG"
        ;;
        i)
            icase="-i"
        ;;
        x)
            OIFS=$IFS
            IFS=','
            for ign in $OPTARG; do
                ignorepattern="$ignorepattern --exclude=$ign"
            done
            IFS=$OIFS
        ;;
        L)
            zimlines="s/\([:-]\)\([0-9][0-9]*\)\([:-]\)/ \+\2\3/"
            #\(\x1b\[.*m\x1b\[K\)
            vimlines="s/\(\x1b.*\)\([:-]\)\(\x1b\[.*\)\([0-9][0-9]*\)\(\x1b.*\)\([:-]\)/\1 +\3\4\5\6/"
        ;;
        A)
            excludefiles=""
        ;;
        \?)
            #echo "Invalid option: -$OPTARG" >&2
            usage
            exit 2
        ;;
    esac
done
#Remove arguments from $@
shift $((OPTIND-1))

#Database location can vary based on installation
if [ "$sigdb" == '-' ]; then
    database='/dev/stdin'
elif [ -f "$GRDIR/$sigdb.db"  ]; then
    database="$GRDIR/$sigdb.db"
elif [ -f "/usr/share/graudit/$sigdb.db" ]; then
    database="/usr/share/graudit/$sigdb.db"
elif [ -f "$HOME/.graudit/$sigdb.db" ]; then
    database="$HOME/.graudit/$sigdb.db"
elif [ -f "$basedir/signatures/$sigdb.db" ]; then
    database="$basedir/signatures/$sigdb.db"
elif [ -f "$basedir/misc/$sigdb.db" ]; then
    database="$basedir/misc/$sigdb.db"
elif [ -f "$HOME/graudit/signatures/$sigdb.db" ]; then
    database="$HOME/graudit/signatures/$sigdb.db"
else
    database="$sigdb"
fi


if [ -z "$1" ]; then
    usage
    exit 2
fi

if [ ! -e $database ]; then
    echo "database path not found: $database, try running graudit with -l" >&2
    usage
    exit 2
fi

# -R is recursive
# -H prints the name of the file
# -C prints # lines of context before and after the match
# -E uses extended regexp
# -f specifies the rule file (signature database)
# -n prints the line number
banner
$BINFILE --color=$color \
         --exclude-dir=.svn \
         --exclude-dir=CVS \
         --exclude-dir=.git \
         $excludefiles \
         $icase $ignorepattern \
         -n -R -H -C "$context" -E \
         -f "$database" $@ | \
sed -e"s/$(printf '\r')//g" -e"s/^\(\x1b\[.*m\x1b\[K\)--\(\x1b\[.*\x1b\[K\)$/\1##############################################\2/" -e"s/^--$/$separator/" | \
sed -e"$vimlines" -e"$zimlines"
SUCCESS=$?
export GREP_COLORS="$OLD_COLORS"
exit $SUCCESS
